package basic

import "fmt"

/**
使用者在使用的时候直接定义
我认为实现者要给我传一个retriever 里面要有个get方法
*/
func User(r Retriever) {
	r.Get()
}

/**
顺手就把接口定义出来了
*/
type Retriever interface {
	Get()
}

/**
实现它
*/
type Admin struct {
	Name string
}

func (admin *Admin) Get() {
	fmt.Println("admin")
}

/**
go 是面向接口编程
go 是 duck typing
大黄鸭是鸭子？ 这个是仁者见仁的问题
只要像鸭子就是鸭子所以只要实现了描述方法就是这个东西。管你活的死的 描述事物的外部接口非内部结构
重点是不是 这个事物要从使用者角度看待。 满足了行为就行了所以接口牛逼了
只要提供能力就得了
接口定义
download          retriever
使用者       ->    实现者

go 中 接口是使用者定义的
这样的灵活性就是 你使用者认为是什么样子的就是什么样子的  而传统的实现者定义了你使用就被框死了很难受

接口 结构体都定义在mock下面 接口可以在建立个文件夹

idea 在结构体名字上选择名字 小灯泡 可以去选择要实现的接口

不需要实现接口，只要实现接口的方法就可以，接口实现是隐士的

var r 接口 = 实现者
fmt.pringxxx("%T %v", r) // t 结构体类型 v 对应的是值

res,err := http.Get()
r,e := httputil.DumpResponse(res)
res.Body.Close()

断言就是一个接口的变量可以断言为其它的类型 空接口很有用
任意类型 interface{}

断言只能对接口变量断言



接口的组合
*/

type A interface {
	Get() string
}
type B interface {
	Post() int
}
type C interface {
	A
	B
	Put() string
}

// go 标准接口
// Stringer 相当于java的toString
type SgerClass struct {
	Name string
}

func (s SgerClass) String() string {
	return s.Name
}

// Reader 这两个流无论网络还是文件跟流有关系就可以用这两个接口自己去实现

// Writer

func st(t Retriever) {
	switch v := t.(type) {
	//case Admin: // 如果方法里面有指针类型接受者这里不能有非指针类型的判断
	//	fmt.Println("ddd")
	case *Admin:
		v.Get()
		fmt.Println("sss")
	}
}

func Inter() {
	fmt.Println("interface")

	// 使用接口约束 实现接口Retriever
	var r Retriever = &Admin{
		"admin",
	}

	User(r)

	// 断言如果Admin里面有定义指针类型接收者这里只能定义断言指针 非指针的报错
	rse := r.(*Admin)
	// switch的形式 变量.(type) switch独有其它地方用报错
	st(r)

	fmt.Println(r, rse)

	var sqx interface{}
	sqx = 1
	fmt.Println(sqx)

	// tostring 实现了Stringer后打印对象可以直接打印出需要信息
	fmt.Println(SgerClass{"admin"})
}
